package de.zainodis.commons.runtime;

import de.zainodis.commons.LogCat;

/**
 * This thread can be stopped by calling {@link Looper#finish()}. It'll give the
 * thread the chance to cleanly finish and execute without sudden interruption.
 * Furthermore this class can be passed a pause-timer via the constructor, which
 * will determine, how long the thread sleeps after each execution cycle of its
 * run method. This thread runs in a loop.
 * 
 * @author fzarrai
 * 
 */
public abstract class Looper extends Thread {

   private static final String TAG = "Looper";

   private boolean isDone = false;
   private boolean isPaused = false;
   private long pauseTimer;

   /**
    * Initializes a new thread object.
    * 
    * @param pauseTimer
    *           the time in milliseconds this thread will sleep after each
    *           execution cycle.
    */
   public Looper(long pauseTimer) {
	 this.pauseTimer = pauseTimer;
   }

   /**
    * This lets the thread cleanly finish it's final execution. Thereafter the
    * thread is considered "done" which means you can't restart it! You'd have
    * to instantiate a new one instead. If you just need to pause thread
    * execution consider {@link Looper#pause()} instead.
    */
   public void finish() {
	 isDone = true;
	 LogCat.i(TAG, "Finishing thread execution.");
   }

   /**
    * Pauses the execution of the thread. This may be revoked by calling
    * {@link Looper#proceed()}.
    */
   public void pause() {
	 isPaused = true;
	 LogCat.i(TAG, "Pausing thread execution.");
   }

   /**
    * Resumes the Looper. This should usually be called after
    * {@link Looper#pause()}. However there is no harm in calling it any time,
    * you want to make sure that the thread proceeds.
    */
   public void proceed() {
	 LogCat.i(TAG, "Resuming thread execution.");
	 isPaused = false;
   }

   @Override
   public void run() {
	 while (!isDone) {
	    if (!isPaused) {
		  // Only execute if the thread has not been paused
		  onRun();
	    }
	    try {
		  sleep(pauseTimer);
	    } catch (InterruptedException e) {
		  LogCat.w(TAG, "Got interrupted.");
	    }
	 }
   }

   /**
    * Gets called each execution cycle - you can handle your "work" here. Must
    * be implemented by subclasses.
    */
   protected abstract void onRun();
}
